package com.chhuang.controller;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.session.SaSessionCustomUtil;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ShearCaptcha;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.chhuang.bean.CaptchaBean;
import com.chhuang.component.I18nMessage;
import com.chhuang.constants.MConstants;
import com.chhuang.core.bean.SaResult;
import com.chhuang.core.enums.SaCode;
import com.chhuang.core.exception.SaException;
import com.chhuang.email.IMailService;
import com.chhuang.email.bean.EmailCaptcha;
import com.chhuang.utils.image.BufferedImageUtils;
import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.Producer;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;

/**
 * @ClassName KaptchaController
 * @Description 获取验证码
 * @Author Darren Huang
 * @Date 2022/11/20 11:37
 * @Version 1.0
 */
@Slf4j
@Validated  //特别注意：@Validated要在controller上标注
@RestController
@RequestMapping("/kaptcha")
@Api(value = "获取验证码接口", tags = "获取验证码接口")
public class KaptchaController {
    /**
     * 验证码提供者
     */
    @Resource
    private Producer kaptchaProducer;
    /**
     * 注入发送邮件的接口
     */
    @Resource
    private IMailService mailService;
    /**
     * 获取国际化资源组件
     */
    @Resource
    private I18nMessage i18nMessage;

    /**
     * 获取图片验证码，保存在session中，用于本地服务校验
     * @param response
     * @param session
     */
    @RequestMapping
    @ApiIgnore
    public void getKaptcha(HttpServletResponse response, HttpSession session) {
        // 生成验证码
        String code = kaptchaProducer.createText();
        log.info("验证码：{}",code);
        BufferedImage image = kaptchaProducer.createImage(code);

        //将验证码存入session
        session.setAttribute(Constants.KAPTCHA_SESSION_KEY, code);

        //将图片输出给浏览器
        response.setContentType("image/png");
        try {
            OutputStream os = response.getOutputStream();
            ImageIO.write(image, "png", os);
        } catch (IOException e) {
            log.error("响应验证码失败:" + e.getMessage());
        }
    }


    /**
     * 把图片base64代码传给前端， 带上sessionId, 提交验证码校验时把sessionId带回来
     * @return
     */
    @GetMapping("/base64")
    @ApiOperation(value = "获取验证码接口", notes = "获取base64图片验证码，用于前端分离服务")
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "获取验证码成功")
    })
    public SaResult<CaptchaBean> getKaptcha() {
        Date now = new Date();
        // 生成验证码
        String code = kaptchaProducer.createText();
        log.info("验证码：{}",code);
        BufferedImage image = kaptchaProducer.createImage(code);
        String base64Image = BufferedImageUtils.bufferedImageToBase64(image);

        //将验证码存入sa-token中的自定义session里
        String saSessionId = "captcha:"+ IdUtil.simpleUUID();//这个sessionId需要传给前端，校验返回
        SaSession saSession = SaSessionCustomUtil.getSessionById(saSessionId);//创建一个用户验证码校验的session
        saSession.set(Constants.KAPTCHA_SESSION_KEY, code);//保存验证码
        saSession.updateTimeout(600L);//设置超时时间
//        SaSessionCustomUtil.deleteSessionById(sessionId); //校验完成后删除

        //把图片base64代码传给前端， 带上sessionId, 提交校验时把sessionId带回来
        CaptchaBean captcha = new CaptchaBean(base64Image, saSessionId, saSession.getTimeout(), now);

        return SaResult.data(captcha);
    }

    /**
     * 邮件验证码
     * @param email
     * @return
     */
    @GetMapping("/toEmail")
    @ApiOperation(value = "发送验证码到指定邮箱", notes = "发送验证码到指定邮箱")
    @ApiImplicitParam(name = "email", value = "邮箱号", required = true, paramType = "query", dataType = "String")
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "用户注册成功")
    })
    public SaResult<CaptchaBean> toEmail(@NotBlank(message = "{email.not_blank}") //特别注意：@Validated要在controller上标注
                                             @Email(message = "{email.valid_fail}")
                                             String email){ //@RequestParam 不写在swagger中调试参数email只能写在地址栏里
        Date now = new Date();
        //5分钟内不重置发送
        String saSessionId = "email_captcha:"+ DigestUtil.md5Hex(email);//这个sessionId需要传给前端，校验返回
        if(SaSessionCustomUtil.isExists(saSessionId)) {
            throw new SaException(SaCode.CAPTCHA_CODE_ALREADY_SEND);
        }

        String subject = i18nMessage.get(MConstants.SEND_EMAIL_CODE_SUBJECT);
        subject = subject.replace(MConstants.SEND_EMAIL_PLACEHOLDER, "chhuangboot");

        String content = i18nMessage.get(MConstants.SEND_EMAIL_CODE_CONTENT);
        String code = kaptchaProducer.createText();
        log.info("验证码：{}",code);
        content = content.replace(MConstants.SEND_EMAIL_PLACEHOLDER, code);

        //将验证码存入sa-token中的自定义session里
        SaSession saSession = SaSessionCustomUtil.getSessionById(saSessionId);//创建一个用户验证码校验的session
        saSession.set(MConstants.SESSION_EMAIL_CAPTCHA_KEY, new EmailCaptcha(email, code, now));//保存验证码
        saSession.updateTimeout(600L);//设置超时时间

        mailService.sendSimpleMail(email, subject, content);

        //把sessionId传给前端, 提交校验时把sessionId带回来
        CaptchaBean captcha = new CaptchaBean(saSessionId, saSession.getTimeout(), now);

        return SaResult.data(captcha);
    }




    /**
     * hutool验证码
     * @param response
     * @param session
     * @throws IOException
     */
    @RequestMapping("/captcha")
    @ApiIgnore
    public void getCaptcha(HttpServletResponse response, HttpSession session) throws IOException {
        //定义图形验证码的长、宽、验证码字符数、干扰线宽度
        ShearCaptcha shearCaptcha = CaptchaUtil.createShearCaptcha(115, 39, 4, 3);
        //图形验证码写出，可以写出到文件，也可以写出到流
        shearCaptcha.write(response.getOutputStream());
        //获取验证码中的文字内容
        String code = shearCaptcha.getCode();
        //将验证码存入session
        session.setAttribute(Constants.KAPTCHA_SESSION_KEY, code);
    }

    /**
     * 把图片base64代码传给前端， 带上sessionId, 提交验证码校验时把sessionId带回来
     * @return
     */
    @GetMapping("/captcha/base64")
    @ApiOperation(value = "获取验证码接口", notes = "获取base64图片验证码，用于前端分离服务")
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "获取验证码成功")
    })
    public SaResult<CaptchaBean> getCaptcha() {
        Date now = new Date();
        //定义图形验证码的长、宽、验证码字符数、干扰线宽度
        ShearCaptcha shearCaptcha = CaptchaUtil.createShearCaptcha(115, 39, 4, 3);
        //获取base64图片验证码
        String base64Image = shearCaptcha.getImageBase64Data();
        //获取验证码中的文字内容
        String code = shearCaptcha.getCode();

        //将验证码存入sa-token中的自定义session里
        String saSessionId = "captcha:"+ IdUtil.simpleUUID();//这个sessionId需要传给前端，校验返回
        SaSession saSession = SaSessionCustomUtil.getSessionById(saSessionId);//创建一个用户验证码校验的session
        saSession.set(Constants.KAPTCHA_SESSION_KEY, code);//保存验证码
        saSession.updateTimeout(600L);//设置超时时间
//        SaSessionCustomUtil.deleteSessionById(sessionId); //校验完成后删除

        //把图片base64代码传给前端， 带上sessionId, 提交校验时把sessionId带回来
        CaptchaBean captcha = new CaptchaBean(base64Image, saSessionId, saSession.getTimeout(), now);

        return SaResult.data(captcha);
    }

    /**
     * 邮件验证码
     * @param email
     * @return
     */
    @GetMapping("/captcha/toEmail")
    @ApiOperation(value = "发送验证码到指定邮箱", notes = "发送验证码到指定邮箱")
    @ApiImplicitParam(name = "email", value = "邮箱号", required = true, paramType = "query", dataType = "String")
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "用户注册成功")
    })
    public SaResult<CaptchaBean> toEmailCaptcha(@NotBlank(message = "{email.not_blank}") //特别注意：@Validated要在controller上标注
                                         @Email(message = "{email.valid_fail}")
                                         String email){ //@RequestParam 不写在swagger中调试参数email只能写在地址栏里
        Date now = new Date();
        //5分钟内不重置发送
        String saSessionId = "email_captcha:"+ DigestUtil.md5Hex(email);//这个sessionId需要传给前端，校验返回
        if(SaSessionCustomUtil.isExists(saSessionId)) {
            throw new SaException(SaCode.CAPTCHA_CODE_ALREADY_SEND);
        }

        String subject = i18nMessage.get(MConstants.SEND_EMAIL_CODE_SUBJECT);
        subject = subject.replace(MConstants.SEND_EMAIL_PLACEHOLDER, "chhuangboot");

        String content = i18nMessage.get(MConstants.SEND_EMAIL_CODE_CONTENT);
        String code = RandomUtil.randomString(4);
        content = content.replace(MConstants.SEND_EMAIL_PLACEHOLDER, code);

        //将验证码存入sa-token中的自定义session里
        SaSession saSession = SaSessionCustomUtil.getSessionById(saSessionId);//创建一个用户验证码校验的session
        saSession.set(MConstants.SESSION_EMAIL_CAPTCHA_KEY, new EmailCaptcha(email, code, now));//保存验证码
        saSession.updateTimeout(600L);//设置超时时间

        mailService.sendSimpleMail(email, subject, content);

        //把sessionId传给前端, 提交校验时把sessionId带回来
        CaptchaBean captcha = new CaptchaBean(saSessionId, saSession.getTimeout(), now);

        return SaResult.data(captcha);
    }
}
